package com.roadmap.biz.message;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;

import org.apache.log4j.Logger;
import org.hibernate.Hibernate;

import com.roadmap.biz.common.BaseManager;
import com.roadmap.biz.common.RdcQueryConst;
import com.roadmap.common.BaseConst;
import com.roadmap.common.BaseEntity;
import com.roadmap.common.RdcLogger;
import com.roadmap.entities.Dialog;
import com.roadmap.entities.Message;
import com.roadmap.entities.ext.DialogExt;
import com.roadmap.entities.ext.MessageExt;
import com.roadmap.exception.ActionNotSupportedException;
import com.roadmap.exception.InvalidActionException;
import com.roadmap.exception.InvalidQueryException;
import com.roadmap.exception.InvalidValueException;
import com.roadmap.exception.NullObjectException;
import com.roadmap.exception.ServerException;
import com.roadmap.repo.db.RdcQuery;

public class MessageManager extends BaseManager {
	private final static Logger _log = RdcLogger
			.getLogger(MessageManager.class);

	public MessageManager(String currentUser, String itemOwner) {
		super(currentUser, itemOwner, Message.class);
	}

	/**
	 * create the same message to one more people. when the user sends a new
	 * message that means a new dialog is started. the new message is the first
	 * one of the dialog.
	 * 
	 * @throws InvalidValueException
	 */
	public void create(String[] recipients, BaseEntity templateMessage)
			throws ServerException, InvalidActionException,
			InvalidValueException {
		checkEntityIsValid(templateMessage);

		Vector<BaseEntity> dialogs = createDialogs(recipients);
		if (dialogs == null || dialogs.isEmpty()) {
			return;
		}

		Message temp = (Message) templateMessage;
		// create new messages
		Vector<BaseEntity> messages = new Vector<BaseEntity>(dialogs.size());
		for (int i = 0; i < dialogs.size(); i++) {
			Message msg = (i == 0) ? temp : temp.clone();
			msg.setDispatcherId(getOwnerId());
			Dialog dlg = (Dialog) dialogs.get(i);
			msg.setDialogId(dlg.getId());
			messages.add(msg);
		}

		getDbUtil().saveOrUpdateEntities(messages);
	}

	/** 创建会话 */
	private Vector<BaseEntity> createDialogs(String[] recipients)
			throws NullObjectException, ServerException {
		if (recipients == null || recipients.length == 0) {
			NullObjectException e = new NullObjectException();
			_log.error("recipients are not valid.", e);
			throw e;
		}

		// create new dialogs firstly
		Vector<BaseEntity> dialogs = new Vector<BaseEntity>();
		for (int i = 0; i < recipients.length; i++) {
			if (recipients[i] == null) {
				continue;
			}
			Dialog dlg = new Dialog();
			dlg.setSponsorId(getOwnerId());
			dlg.setParticipatorId(recipients[i]);
			dialogs.add(dlg);
		}

		getDbUtil().saveOrUpdateEntities(dialogs);

		return dialogs;
	}

	/** get the messages sent by the user */
	@Override
	public List getEntitiesOfOwner() throws ServerException {
		RdcQuery query = getDbUtil().createNativeSQLQuery(RdcQueryConst.SQL_SENT_MSGS_USER_BY_USER);
		query.addEntity("m", Message.class);
		query.setParameter("me", getOwnerId());
		query.addScalar("aspirantId", Hibernate.STRING);
		query.addScalar("realName", Hibernate.STRING);
		query.setMaxResults(BaseConst.MESSAGE_MAX_RESULTS);
		List results = query.getResults();
		if (results == null || results.isEmpty()) {
			return null;
		}
		
		results = getResultsForSpecifiedPage(results);
		List<MessageExt> messages = new ArrayList<MessageExt>();
		Iterator iter = results.iterator();
		while (iter.hasNext()) {
			Object[] result = (Object[]) iter.next();
			MessageExt msg = new MessageExt((Message) result[0]);
			msg.setRecipientId((String) result[1]);
			msg.setRecipientName((String) result[2]);
			messages.add(msg);
		}
		
		return messages;
	}

	/** get the messages sent to the user */
	@Override
	public List<MessageExt> getExecutableEntities()
			throws ActionNotSupportedException, InvalidQueryException,
			InvalidValueException, ServerException {
		RdcQuery query = getDbUtil().createNativeSQLQuery(RdcQueryConst.SQL_RECEIEVED_MSGS_USER_BY_USER);
		query.addEntity("m", Message.class);
		query.setParameter("me", getOwnerId());
		query.addScalar("aspirantId", Hibernate.STRING);
		query.addScalar("realName", Hibernate.STRING);
		query.setMaxResults(BaseConst.MESSAGE_MAX_RESULTS);
		List results = query.getResults();
		results = getResultsForSpecifiedPage(results);
 		return getReceivedMessages(results);
	}

	/** 用户收到的消息 */
	private List<MessageExt> getReceivedMessages(List results)
			throws NullObjectException, ServerException {
		if (results == null || results.isEmpty()) {
			return null;
		}

		List<MessageExt> messages = new ArrayList<MessageExt>();
		Vector<BaseEntity> msgVec = new Vector<BaseEntity>();
		Iterator iter = results.iterator();
		while (iter.hasNext()) {
			Object[] result = (Object[]) iter.next();
			Message m = (Message) result[0];
			// create an extended message
			MessageExt msg = new MessageExt(m);
			msg.setDispatcherId((String) result[1]);
			msg.setDispatcherName((String) result[2]);
			messages.add(msg);

			// change the message's status
			if (m.getStatus() == BaseConst.MESSAGE_STATUS_UNREAD) {
				m.setStatus(BaseConst.MESSAGE_STATUS_READ);
				msgVec.add(m);
			}
		}

		// change the new messages to READ
		if (msgVec != null && !msgVec.isEmpty()) {
			getDbUtil().saveOrUpdateEntities(msgVec);
		}
		
		return messages;
	}

	/** get the latest message specified by the dialog id */
	@Override
	public BaseEntity getEntityExt(String entityId) throws NullObjectException,
			InvalidQueryException, ServerException, InvalidValueException {
		RdcQuery query = getDbUtil().createNativeSQLQuery(RdcQueryConst.SQL_MSGS_BY_DIALOG);
		query.addEntity("m", Message.class);
		query.setParameter("dlgid", entityId);
		query.addScalar("realName", Hibernate.STRING);
		List results = query.getResults();
		List<MessageExt> messages = getDialogMessages(results);
		if (messages == null || messages.isEmpty()) {
			return null;
		}

		// get the dialog people's names
		query = getDbUtil().createNativeSQLQuery(RdcQueryConst.SQL_USERS_BY_DIALOG);
		query.addEntity("d", Dialog.class);
		query.setParameter("dlgid", entityId);
		query.addScalar("aspirantId", Hibernate.STRING);
		query.addScalar("realName", Hibernate.STRING);
		results = query.getResults();
		DialogExt dialog = getDialogExt(results);
		if(dialog != null) {
			dialog.setMessages(messages);
		}
		return dialog;
	}

	/** 处理会话的消息 */
	private List<MessageExt> getDialogMessages(List results)
			throws NullObjectException, ServerException {
		if (results == null || results.isEmpty()) {
			return null;
		}

		List<MessageExt> messages = new ArrayList<MessageExt>();
		Vector<BaseEntity> msgVec = new Vector<BaseEntity>();
		results = getResultsForSpecifiedPage(results);
		Iterator iter = results.iterator();
		while (iter.hasNext()) {
			Object[] result = (Object[]) iter.next();
			Message m = (Message) result[0];
			MessageExt msg = new MessageExt(m);
			msg.setDispatcherName((String) result[1]);
			messages.add(msg);

			// 修改消息状态
			if (msg.getStatus() == BaseConst.MESSAGE_STATUS_UNREAD
					&& !m.getDispatcherId().equals(getOwnerId())) {
				m.setStatus(BaseConst.MESSAGE_STATUS_READ);
				msgVec.add(m);
			}
		}

		// update the message's status in database
		if (!msgVec.isEmpty()) {
			getDbUtil().saveOrUpdateEntities(msgVec);
		}
		return messages;
	}

	/** 得到会话 */
	private DialogExt getDialogExt(List results) {
		// the size of returned results should be 2.
		if (results == null || results.size() != 2) {
			return null;
		}

		DialogExt dialog = null;
		Iterator iter = results.iterator();
		while (iter.hasNext()) {
			Object[] result = (Object[]) iter.next();
			if (dialog == null) {
				dialog = new DialogExt((Dialog) result[0]);
			}
			// assign the right names
			if (dialog.getSponsorId().equals((String) result[1])) {
				dialog.setSponsorName((String) result[2]);
			}
			else {
				dialog.setParticipatorName((String) result[2]);
			}
		}

		return dialog;
	}
}
